

#ifndef _CHANNEL_H_
#define _CHANNEL_H_

#include "Timestamp.hpp"
#include "noncopyable.hpp"
#include <cmath>
#include <functional>
#include <memory>


namespace zephyr {

class EventLoop;

class Channel : noncopyable {
  public:
    using EventCallback = std::function<void()>;
    using ReadEventCallback = std::function<void(Timestamp)>;

    Channel(EventLoop *loop, int fd);
    ~Channel();

    void handleEvent(Timestamp recviveTime);

    void setReadCallback(ReadEventCallback callback) { m_readCallback = std::move(callback); }

    void setWriteCallback(EventCallback callback) { m_writeCallback = std::move(callback); }

    void setCloseCallback(EventCallback callback) { m_closeCallback = std::move(callback); }

    void setErrorCallback(EventCallback callback) { m_errorCallback = std::move(callback); }

    void enableReading() { m_events |= k_ReadEvent; update(); }

    void disableReading() { m_events &= ~k_ReadEvent; update(); }

    void enableWriting() { m_events |= k_WriteEvent; update(); }

    void disableWriting() { m_events &= ~k_WriteEvent; update(); }

    void disableAll() { m_events = k_NoneEvent; update(); }

    void set_realEvents(int revt) { m_revents = revt; }

    bool isNoneEvent() const { return m_events == k_NoneEvent; }
    bool isWriting() const { return m_events & k_WriteEvent; }
    bool isReading() const { return m_events & k_ReadEvent; }
    
    // 防止channel被手动remove掉，channel还在执行回调操作
    void tie(const std::shared_ptr<void> &);

    int fd() const { return m_fd; }
    int events() const { return m_events; }
    int index() {return m_index; }
    void setIndex(int index) { m_index = index; }

    EventLoop *ownerLoop() { return m_loop; }
    void remove();

  private:
    void update();
    void handleEventWithGuard(Timestamp recviveTime);

  private:

    EventLoop *m_loop; // fd所在的事件循环
    const int m_fd;
    int m_events; // fd 感兴趣的事件
    int m_revents; // Poller 返回的具体发生的事件
    int m_index;

    std::weak_ptr<void> m_tie; // TODO:
    bool m_tied;

    static const int k_NoneEvent;
    static const int k_ReadEvent;
    static const int k_WriteEvent;

    ReadEventCallback m_readCallback;
    EventCallback m_writeCallback;
    EventCallback m_closeCallback;
    EventCallback m_errorCallback;
};

}

#endif // _CHANNEL_H_